home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Frameworks / Hsoi's App Shell 1.0a4 / HAS Other Source / WASTE 1.3a4 Distribution / WASTE 1.3a4 / Source / WEHighLevelEditing.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-04  |  34.1 KB  |  1,575 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEHighLevelEditing.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  High-Level Editing Routines
  6.  *
  7.  *  Copyright (c) 1993-1997 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. pascal void _WEPushAction(WEActionHandle hAction)
  18. {
  19.     WEPtr pWE = *((*hAction)->hOwner);
  20.     WEActionHandle hLast;
  21.  
  22.     // find the last action in the given stack
  23.     for ( hLast = hAction; (*hLast)->hNext != nil; hLast = (*hLast)->hNext )
  24.         ;
  25.  
  26.     // prepend hAction in front of the action stack
  27.     (*hLast)->hNext = pWE->hActionStack;
  28.     pWE->hActionStack = hAction;
  29. }
  30.  
  31. pascal OSErr _WENewAction(SInt32 rangeStart, SInt32 rangeEnd, SInt32 newTextLength,
  32.                             WEActionKind actionKind, WEActionFlags actionFlags,
  33.                             WEHandle hWE, WEActionHandle *hAction)
  34. {
  35.     WEAction *pAction;
  36.     OSErr err;
  37.  
  38.     // allocate a new action record
  39.     if ((err = _WEAllocate(sizeof(WEAction), kAllocClear, (Handle *)hAction)) != noErr)
  40.     {
  41.         goto cleanup1;
  42.     }
  43.  
  44.     // lock it down
  45.     HLock((Handle) *hAction);
  46.     pAction = **hAction;
  47.  
  48.     // fill in the fields
  49.     pAction->hOwner = hWE;
  50.     pAction->delRangeStart = rangeStart;
  51.     pAction->delRangeLength = newTextLength;
  52.     pAction->insRangeLength = rangeEnd - rangeStart;
  53.     pAction->actionKind = actionKind;
  54.     pAction->actionFlags = actionFlags;
  55.  
  56.     // remember selection range
  57.     WEGetSelection(&pAction->hiliteStart, &pAction->hiliteEnd, hWE);
  58.  
  59.     // allocate a handle to hold the text to be saved, unless otherwise specified
  60.     if ((actionFlags & weAFDontSaveText) == 0)
  61.     {
  62.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hText)) != noErr)
  63.         {
  64.             goto cleanup1;
  65.         }
  66.     }
  67.  
  68.     // allocate a handle to hold the styles to be saved, unless otherwise specified
  69.     if ((actionFlags & weAFDontSaveStyles) == 0)
  70.     {
  71.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hStyles)) != noErr)
  72.         {
  73.             goto cleanup1;
  74.         }
  75.     }
  76.  
  77. #if WASTE_OBJECTS
  78.     // allocate a handle to hold the "soup" to be saved, unless otherwise specified
  79.     if ((actionFlags & weAFDontSaveSoup) == 0)
  80.     {
  81.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hSoup)) != noErr)
  82.         {
  83.             goto cleanup1;
  84.         }
  85.     }
  86. #endif
  87.  
  88.     // make a copy of text range
  89.     if ((err = WECopyRange(rangeStart, rangeEnd, pAction->hText, (Handle) pAction->hStyles, pAction->hSoup, hWE)) != noErr)
  90.     {
  91.         goto cleanup1;
  92.     }
  93.  
  94.     // unlock action record
  95.     HUnlock((Handle) *hAction);
  96.  
  97.     // skip clean-up section
  98.     goto cleanup0;
  99.  
  100. cleanup1:
  101.     // clean up
  102.     _WEForgetHandle(&pAction->hText);
  103.     _WEForgetHandle(&pAction->hStyles);
  104. #if WASTE_OBJECTS
  105.     _WEForgetHandle(&pAction->hSoup);
  106. #endif
  107.     _WEForgetHandle((Handle *)hAction);
  108.  
  109. cleanup0:
  110.     // return result code
  111.     return err;
  112.  
  113. }
  114.  
  115. pascal void _WEDisposeAction(WEActionHandle hAction)
  116. {
  117.     WEAction *pAction;
  118.     WEActionHandle hNext;
  119.  
  120.     for ( ; hAction != nil; hAction = hNext )
  121.     {
  122.         // lock the action record
  123.         HLock((Handle) hAction);
  124.         pAction = *hAction;
  125.         hNext = pAction->hNext;
  126.  
  127.         // throw away text, styles and soup
  128.         _WEForgetHandle(&pAction->hText);
  129.         _WEForgetHandle(&pAction->hStyles);
  130. #if WASTE_OBJECTS
  131.         _WEForgetHandle(&pAction->hSoup);
  132. #endif
  133.  
  134.         // throw away the action record itself
  135.         DisposeHandle((Handle) hAction);
  136.     }
  137. }
  138.  
  139. pascal void _WEForgetAction(WEActionHandle *hAction)
  140. {
  141.     WEActionHandle theAction;
  142.  
  143.     theAction = *hAction;
  144.     if (theAction != nil)
  145.     {
  146.         *hAction = nil;
  147.         _WEDisposeAction(theAction);
  148.     }
  149. }
  150.  
  151. pascal OSErr _WEDoAction(WEActionHandle hAction)
  152. {
  153.     WEActionHandle hRedoAction;
  154.     WEAction *pAction;
  155.     WEHandle hWE;
  156.     WEPtr pWE;
  157.     SInt32 offset, delOffset, insOffset;
  158.     SInt32 redrawStart, redrawEnd;
  159.     Boolean saveActionLock, saveWELock, saveTextLock;
  160.     OSErr err;
  161.  
  162.     // sanity check: make sure hAction isn't nil
  163.     if (hAction == nil)
  164.     {
  165.         return nilHandleErr;
  166.     }
  167.  
  168.     // get handle to associated WE instance
  169.     hWE = (*hAction)->hOwner;
  170.  
  171.     // lock the WE record
  172.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  173.     pWE = *hWE;
  174.  
  175.     // return an error code if this instance is read-only
  176.     err = weReadOnlyErr;
  177.     if (BTST(pWE->features, weFReadOnly))
  178.     {
  179.         goto cleanup;
  180.     }
  181.  
  182.     // stop any ongoing inline input session
  183.     WEStopInlineSession(hWE);
  184.  
  185.     // hide selection highlighting and the caret
  186.     _WEHiliteRange(pWE->selStart, pWE->selEnd, hWE);
  187.     if (BTST(pWE->flags, weFCaretVisible))
  188.     {
  189.         _WEBlinkCaret(hWE);
  190.     }
  191.  
  192.     redrawStart = LONG_MAX;
  193.     redrawEnd = 0;
  194.  
  195.     for ( ; hAction != nil; hAction = (*hAction)->hNext )
  196.     {
  197.         // lock the action record
  198.         saveActionLock = _WESetHandleLock((Handle) hAction, true);
  199.         pAction = *hAction;
  200.         offset = pAction->delRangeStart;
  201.         delOffset = offset + pAction->delRangeLength;
  202.         insOffset = offset + pAction->insRangeLength;
  203.  
  204.         // update the modification count of the affected WE instance
  205.         // note that undoing a change _decrements_ the modification count,
  206.         // while redoing the change increments it again
  207.         if (pAction->actionFlags & weAFIsRedo)
  208.         {
  209.             pWE->modCount++;
  210.         }
  211.         else
  212.         {
  213.             pWE->modCount--;
  214.         }
  215.  
  216.         // if undo support is enabled, save the range to be affected by this action
  217.         if (BTST(pWE->features, weFUndoSupport))
  218.         {
  219.             if (_WENewAction(offset, delOffset, pAction->insRangeLength, pAction->actionKind,
  220.                 (pAction->actionFlags ^ weAFIsRedo), hWE, &hRedoAction) == noErr)
  221.             {
  222.                 _WEPushAction(hRedoAction);
  223.             }
  224.         }
  225.  
  226.         if (pAction->hText != nil)
  227.         {
  228.             // delete the range to replace
  229.             if ((err = _WEDeleteRange(offset, delOffset, hWE)) != noErr)
  230.             {
  231.                 goto cleanup;
  232.             }
  233.  
  234.             // insert the saved text
  235.             saveTextLock = _WESetHandleLock(pAction->hText, true);
  236.             err = _WEInsertText(offset, *pAction->hText, pAction->insRangeLength, hWE);
  237.             _WESetHandleLock(pAction->hText, saveTextLock);
  238.             if (err != noErr)
  239.             {
  240.                 goto cleanup;
  241.             }
  242.         }
  243.  
  244.         // apply the saved styles, if any
  245.         if (pAction->hStyles != nil)
  246.         {
  247.             if ((err = _WEApplyStyleScrap(offset, insOffset, (StScrpHandle) pAction->hStyles, hWE)) != noErr)
  248.             {
  249.                 goto cleanup;
  250.             }
  251.         }
  252.  
  253. #if WASTE_OBJECTS
  254.         // the same goes for the soup
  255.         if (pAction->hSoup != nil)
  256.         {
  257.             if ((err = _WEApplySoup(offset, pAction->hSoup, hWE)) != noErr)
  258.             {
  259.                 goto cleanup;
  260.             }
  261.         }
  262. #endif
  263.  
  264.         // adjust redraw range (??? will this work with "complex" action stacks ???)
  265.         if (offset < redrawStart)
  266.         {
  267.             redrawStart = offset;
  268.         }
  269.         if (insOffset > redrawEnd)
  270.         {
  271.             redrawEnd = insOffset;
  272.         }
  273.  
  274.         // unlock action record
  275.         _WESetHandleLock((Handle) hAction, saveActionLock);
  276.  
  277.     } // for
  278.  
  279.     // restore the original selection range
  280.     pWE->selStart = pAction->hiliteStart;
  281.     pWE->selEnd = pAction->hiliteEnd;
  282.  
  283.     // redraw the text
  284.     if ((err = _WERedraw(redrawStart, redrawEnd, hWE)) != noErr)
  285.     {
  286.         goto cleanup;
  287.     }
  288.  
  289.     // clear result code
  290.     err = noErr;
  291.  
  292. cleanup:
  293.     // unlock the WE record
  294.     _WESetHandleLock((Handle) hWE, saveWELock);
  295.  
  296.     // return result code
  297.     return err;
  298. }
  299.  
  300. pascal OSErr WEUndo(WEHandle hWE)
  301. {
  302.     WEPtr pWE;
  303.     WEActionHandle hAction;
  304.     Boolean saveWELock;
  305.     OSErr err;
  306.  
  307.     // lock the WE record
  308.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  309.     pWE = *hWE;
  310.  
  311.     // "detach" the action stack from the WE instance
  312.     hAction = pWE->hActionStack;
  313.     pWE->hActionStack = nil;
  314.  
  315.     if (hAction != nil)
  316.     {
  317.         // perform the action...
  318.         err = _WEDoAction(hAction);
  319.  
  320.         // ...and throw it away
  321.         _WEDisposeAction(hAction);
  322.     }
  323.     else
  324.     {
  325.         // return an error code if the undo buffer is empty
  326.         err = weCantUndoErr;
  327.     }
  328.  
  329.     // unlock the WE record
  330.     _WESetHandleLock((Handle) hWE, saveWELock);
  331.  
  332.     return err;
  333. }
  334.  
  335. pascal void WEClearUndo(WEHandle hWE)
  336. {
  337.     WEPtr pWE = *hWE;
  338.  
  339.     // dispose of the action chain associated with the given WE instance,
  340.     // unless weFAccumulateUndos is set
  341.     if (! BTST(pWE->flags, weFAccumulateUndos))
  342.     {
  343.         _WEForgetAction(&pWE->hActionStack);
  344.     }
  345. }
  346.  
  347. pascal WEActionKind WEGetUndoInfo(Boolean *redoFlag, WEHandle hWE)
  348. {
  349.     WEActionHandle hAction;
  350.     WEActionKind theKind = weAKNone;
  351.     Boolean theFlag = false;
  352.  
  353.     if ((hAction = (*hWE)->hActionStack) != nil)
  354.     {
  355.         theKind = (*hAction)->actionKind;
  356.         theFlag = (((*hAction)->actionFlags & weAFIsRedo) != 0);
  357.     }
  358.  
  359.     if (redoFlag != nil)
  360.     {
  361.         *redoFlag = theFlag;
  362.     }
  363.     return theKind;
  364. }
  365.  
  366. pascal OSErr WEBeginAction(WEHandle hWE)
  367. {
  368.     WEPtr pWE = *hWE;
  369.  
  370.     if (BTST(pWE->flags, weFAccumulateUndos))
  371.     {
  372.         //    calling WEBeginAction twice in a row
  373.         //    is considered a protocol error
  374.         return weProtocolErr;
  375.     }
  376.  
  377.     //    set weFAccumulateUndos so that each new change will add to,
  378.     //    rather than replace, the existing action stack
  379.     BSET(pWE->flags, weFAccumulateUndos);
  380.  
  381.     //    start with a fresh action stack
  382.     _WEForgetAction(&pWE->hActionStack);
  383.  
  384.     return noErr;
  385. }
  386.  
  387. pascal OSErr WEEndAction(WEActionKind actionKind, WEHandle hWE)
  388. {
  389.     WEPtr pWE = *hWE;
  390.  
  391.     if (! BTST(pWE->flags, weFAccumulateUndos))
  392.     {
  393.         //    a call to WEEndAction not balanced by a previous
  394.         //    call to WEBeginAction is a protocol error
  395.         return weProtocolErr;
  396.     }
  397.  
  398.     //    stop accumulating actions
  399.     BCLR(pWE->flags, weFAccumulateUndos);
  400.  
  401.     //    make sure we have a non-empty action stack
  402.     if (pWE->hActionStack == nil)
  403.     {
  404.         return weCantUndoErr;
  405.     }
  406.  
  407.     //    set the action kind
  408.     (*pWE->hActionStack)->actionKind = actionKind;
  409.  
  410.     return noErr;
  411. }
  412.  
  413. pascal UInt32 WEGetModCount(WEHandle hWE)
  414. {
  415.     return (*hWE)->modCount;
  416. }
  417.  
  418. pascal void WEResetModCount(WEHandle hWE)
  419. {
  420.     (*hWE)->modCount = 0;
  421.     _WEForgetAction(&(*hWE)->hActionStack);
  422. }
  423.  
  424. pascal void _WEAdjustUndoRange(SInt32 moreBytes, WEHandle hWE)
  425. {
  426.     WEActionHandle hAction;
  427.  
  428.     if ((hAction = (*hWE)->hActionStack) != nil)
  429.     {
  430.         (*hAction)->delRangeLength += moreBytes;
  431.     }
  432. }
  433.  
  434. pascal OSErr _WETypeChar(char theByte, WEHandle hWE)
  435. {
  436.     WEPtr pWE;
  437.     char db[2];
  438.     SInt32 offset, endOffset, charLength;
  439.     OSErr err;
  440.  
  441.     pWE = *hWE;                    // the WE record must be already locked
  442.     charLength = 1;                // assume 1-byte character by default
  443.     db[0] = theByte;
  444.     offset = pWE->selStart;
  445.  
  446.     // delete current selection, if any
  447.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  448.     {
  449.         goto cleanup2;
  450.     }
  451.  
  452.     pWE->selEnd = offset; // needed in case we take a premature exit
  453.  
  454.     // make sure the font script is synchronized with the keyboard script
  455.     _WESynchNullStyle(hWE);
  456.  
  457.     if (BTST(pWE->flags, weFDoubleByte))
  458.     {
  459.  
  460.         // special processing for double-byte characters
  461.         if (pWE->firstByte != 0)
  462.         {
  463.  
  464.             // if this byte is the second half of a double-byte character,
  465.             // insert the two bytes at the same time (flush the double-byte cache)
  466.             db[0] = pWE->firstByte;
  467.             db[1] = theByte;
  468.             charLength = 2;
  469.             pWE->firstByte = 0;
  470.         }
  471.         else
  472.         {
  473.  
  474.             // if theByte is the first half of a double-byte character, just cache it and exit
  475.             if (CallWECharByteProc(&theByte, 0, FontToScript(pWE->nullStyle.runStyle.tsFont),
  476.                 hWE, pWE->charByteHook) == smFirstByte)
  477.             {
  478.                 pWE->firstByte = theByte;
  479.                 return noErr;
  480.             }
  481.         }
  482.  
  483.     } // if double-byte script installed
  484.  
  485.     // insert the new character into the text
  486.     if ((err = _WEInsertText(offset, db, charLength, hWE)) != noErr)
  487.     {
  488.         goto cleanup2;
  489.     }
  490.  
  491.     // adjust undo buffer for the new character
  492.     _WEAdjustUndoRange(charLength, hWE);
  493.  
  494.     // invalid the null style
  495.     BCLR(pWE->flags, weFUseNullStyle);
  496.  
  497.     // move the insertion point after the new character
  498.     endOffset = offset + charLength;
  499.     pWE->selStart = endOffset;
  500.     pWE->selEnd = endOffset;
  501.  
  502.     // redraw the text
  503.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  504.     {
  505.         goto cleanup2;
  506.     }
  507.  
  508. cleanup1:
  509.     // clear result code
  510.     err = noErr;
  511.  
  512. cleanup2:
  513.     // return result code
  514.     return err;
  515.  
  516. }
  517.  
  518. pascal OSErr _WEBackspace(WEHandle hWE)
  519. {
  520.     // this routine is called by WEKey to handle the backspace key
  521.  
  522.     WEPtr pWE = *hWE;    // assume WE record is already locked
  523.     WEAction *pAction;
  524.     SInt32 rangeStart, rangeEnd, charLength;
  525.     WERunInfo runInfo;
  526.     char db[2];
  527.     Boolean saveActionLock;
  528.     OSErr err;
  529.  
  530.     // calculate the text range to delete
  531.     // if the selection is non-empty, delete that
  532.     rangeStart = pWE->selStart;
  533.     rangeEnd = pWE->selEnd;
  534.     if (rangeStart == rangeEnd)
  535.     {
  536.  
  537.         // otherwise the selection is an insertion point
  538.         // do nothing if insertion point is at the beginning of the text
  539.         if (rangeStart == 0)
  540.         {
  541.             return noErr;
  542.         }
  543.  
  544.         // determine the byte-type of the character preceding the insertion point
  545.         charLength = (WECharByte(rangeStart - 1, hWE) == smSingleByte) ? 1 : 2;
  546.         rangeStart -= charLength;
  547.  
  548.         if (pWE->hActionStack != nil)
  549.         {
  550.             // UNDO SUPPORT FOR BACKSPACES
  551.  
  552.             // lock the action record
  553.             saveActionLock = _WESetHandleLock((Handle) pWE->hActionStack, true);
  554.             pAction = *pWE->hActionStack;
  555.  
  556.             // backspaces over the newly entered text aren't a problem
  557.             if (pAction->delRangeLength > 0)
  558.             {
  559.                 pAction->delRangeLength -= charLength;
  560.             }
  561.             else
  562.             {
  563.  
  564.                 // the hard part comes when backspacing past the new text because
  565.                 // the user is about to delete a character not included in the block we saved
  566.                 db[0] = WEGetChar(rangeStart, hWE);
  567.                 if (charLength == 2)
  568.                 {
  569.                     db[1] = WEGetChar(rangeStart + 1, hWE);
  570.                 }
  571.  
  572.                 // prepend the character to be deleted to the beginning of our saved text handle
  573.                 if ((err = _WESplice(pAction->hText, &db, charLength, 0)) != noErr)
  574.                 {
  575.                     return err;
  576.                 }
  577.  
  578.                 // adjust internal counters
  579.                 pAction->insRangeLength += charLength;
  580.                 pAction->delRangeStart -= charLength;
  581.  
  582.                 // get style run info associated with the about-to-be-deleted character
  583.                 WEGetRunInfo(rangeStart, &runInfo, hWE);
  584.  
  585.                 // prepend a new style element to our style scrap, if necessary
  586.                 if ((err = _WEPrependStyle(pAction->hStyles, &runInfo, charLength)) != noErr)
  587.                 {
  588.                     return err;
  589.                 }
  590.  
  591. #if WASTE_OBJECTS
  592.                 // do the same with our object "soup"
  593.                 if ((err = _WEPrependObject(pAction->hSoup, &runInfo, charLength)) != noErr)
  594.                 {
  595.                     return err;
  596.                 }
  597. #endif
  598.  
  599.             } // if deleting old text
  600.  
  601.             // unlock the action record
  602.             _WESetHandleLock((Handle) pWE->hActionStack, saveActionLock);
  603.  
  604.         } // if undo support is enabled
  605.     } // if selection is empty
  606.  
  607.     if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  608.     {
  609.         return err;
  610.     }
  611.  
  612.     // keep track of current selection range
  613.     pWE->selStart = rangeStart;
  614.     pWE->selEnd = rangeStart;
  615.  
  616.     // redraw the text
  617.     err = _WERedraw(rangeStart, rangeStart, hWE);
  618.  
  619.     return err;
  620. }
  621.  
  622. pascal OSErr _WEForwardDelete(WEHandle hWE)
  623. {
  624.  
  625.     // this routine is called by WEKey to handle the forward delete key
  626.  
  627.     WEPtr pWE = *hWE;    // assume WE record is already locked
  628.     WEAction *pAction;
  629.     SInt32 rangeStart, rangeEnd, charLength;
  630.     WERunInfo runInfo;
  631.     char db[2];
  632.     Boolean saveActionLock;
  633.     OSErr err;
  634.  
  635.     // calculate the text range to delete
  636.     // if the selection is non-empty, delete that
  637.     rangeStart = pWE->selStart;
  638.     rangeEnd = pWE->selEnd;
  639.     if (rangeStart == rangeEnd)
  640.     {
  641.  
  642.         // otherwise the selection is an insertion point
  643.         // do nothing if insertion point is at the end of the text
  644.         if (rangeStart == pWE->textLength)
  645.         {
  646.             return noErr;
  647.         }
  648.  
  649.         // determine the byte-type of the character following the insertion point
  650.         charLength = (WECharByte(rangeStart, hWE) == smSingleByte) ? 1 : 2;
  651.         rangeEnd = rangeStart + charLength;
  652.  
  653.         if (pWE->hActionStack != nil)
  654.         {
  655.  
  656.             // UNDO SUPPORT FOR FORWARD DELETE
  657.  
  658.             // lock the action record
  659.             saveActionLock = _WESetHandleLock((Handle) pWE->hActionStack, true);
  660.             pAction = *pWE->hActionStack;
  661.  
  662.             // make a copy of the character about to be deleted
  663.             db[0] = WEGetChar(rangeStart, hWE);
  664.             if (charLength == 2)
  665.             {
  666.                 db[1] = WEGetChar(rangeStart + 1, hWE);
  667.             }
  668.  
  669.             // append it to the end of our saved text handle
  670.             if ((err = _WESplice(pAction->hText, &db, charLength, -1)) != noErr)
  671.             {
  672.                 return err;
  673.             }
  674.  
  675.             // get style run info associated with the about-to-be-deleted character
  676.             WEGetRunInfo(rangeStart, &runInfo, hWE);
  677.  
  678.             // append a new style element to our style scrap, if necessary
  679.             if ((err = _WEAppendStyle(pAction->hStyles, &runInfo, pAction->insRangeLength)) != noErr)
  680.             {
  681.                 return err;
  682.             }
  683.  
  684. #if WASTE_OBJECTS
  685.             // do the same with our object soup
  686.             if ((err = _WEAppendObject(pAction->hSoup, &runInfo, pAction->insRangeLength)) != noErr)
  687.             {
  688.                 return err;
  689.             }
  690. #endif
  691.  
  692.             // adjust internal counters
  693.             pAction->insRangeLength += charLength;
  694.  
  695.             // unlock the action record
  696.             _WESetHandleLock((Handle) pWE->hActionStack, saveActionLock);
  697.  
  698.         } // if undo support is enabled
  699.     } // if selection is empty
  700.  
  701.     if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  702.     {
  703.         return err;
  704.     }
  705.  
  706.     // keep track of current selection range
  707.     pWE->selStart = rangeStart;
  708.     pWE->selEnd = rangeStart;
  709.  
  710.     // redraw the text
  711.     err = _WERedraw(rangeStart, rangeStart, hWE);
  712.  
  713.     return err;
  714. }
  715.  
  716. pascal Boolean WEIsTyping(WEHandle hWE)
  717. {
  718.     // return true if we're tracking a typing sequence in the specified WE instance
  719.  
  720.     WEPtr pWE = *hWE;
  721.     WEAction *pAction;
  722.  
  723.     // there must be an undo buffer
  724.     if (pWE->hActionStack == nil)
  725.     {
  726.         return false;
  727.     }
  728.  
  729.     pAction = *pWE->hActionStack;
  730.  
  731.     // the action kind must be "typing" and the redo flag must be clear
  732.     if ((pAction->actionKind != weAKTyping) || ((pAction->actionFlags & weAFIsRedo) != 0))
  733.     {
  734.         return false;
  735.     }
  736.  
  737.     // finally, the selection range mustn't have moved since the last WEKey
  738.     if ((pWE->selStart != pWE->selEnd) ||
  739.         (pWE->selStart != pAction->delRangeStart + pAction->delRangeLength))
  740.     {
  741.         return false;
  742.     }
  743.  
  744.     return true;
  745. }
  746.  
  747. pascal void WEKey(SInt16 key, EventModifiers modifiers, WEHandle hWE)
  748. {
  749.     WEPtr pWE;
  750.     WEActionHandle hAction;
  751.     Boolean saveWELock;
  752.  
  753.     // lock the WE record
  754.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  755.     pWE = *hWE;
  756.  
  757.     // hide the caret if it's showing
  758.     if (BTST(pWE->flags, weFCaretVisible))
  759.     {
  760.         _WEBlinkCaret(hWE);
  761.     }
  762.  
  763.     // hide the cursor (it will show again as soon as it's moved)
  764.     ObscureCursor();
  765.  
  766.     // dispatch on key class (arrow keys, printable characters, backspace)
  767.     if ((key >= kArrowLeft) && (key <= kArrowDown))
  768.     {
  769.         _WEDoArrowKey(key, modifiers, hWE);
  770.     }
  771.     else
  772.     {
  773.  
  774.         // non-arrow keys modify the text, so make sure editing is allowed
  775.         if (!BTST(pWE->features, weFReadOnly))
  776.         {
  777.             // are we tracking a typing sequence?
  778.             if (!WEIsTyping(hWE))
  779.             {
  780.                 // nope;  start a new one
  781.                 // increment modification count
  782.                 pWE->modCount++;
  783.  
  784.                 // if undo support is enabled, create a new action to keep track of typing
  785.                 if (BTST(pWE->features, weFUndoSupport))
  786.                 {
  787.                     WEClearUndo(hWE);
  788.                     if (_WENewAction(pWE->selStart, pWE->selEnd, 0, weAKTyping, 0, hWE, &hAction) == noErr)
  789.                     {
  790.                         _WEPushAction(hAction);
  791.                     }
  792.                 }
  793.             } // if WEIsTyping
  794.  
  795.             if (key == kBackspace)
  796.             {
  797.                 _WEBackspace(hWE);
  798.             }
  799.             else if (key == kForwardDelete)
  800.             {
  801.                 _WEForwardDelete(hWE);
  802.             }
  803.             else
  804.             {
  805.                 _WETypeChar(key, hWE);
  806.             }
  807.         } // if not read-only
  808.     }
  809.  
  810.     // unlock the WE record
  811.     _WESetHandleLock((Handle) hWE, saveWELock);
  812. }
  813.  
  814. pascal OSErr WEInsert(Ptr textPtr, SInt32 textLength, StScrpHandle hStyles, Handle hSoup, WEHandle hWE)
  815. {
  816. #if !WASTE_OBJECTS
  817. #pragma unused(hSoup)
  818. #endif
  819.     WEPtr pWE;
  820.     SInt32 offset, endOffset;
  821.     WEActionHandle hAction;
  822.     SInt16 intPasteAction;
  823.     Boolean saveWELock;
  824.     char space = kSpace;
  825.     OSErr err;
  826.  
  827.     // lock the WE record
  828.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  829.     pWE = *hWE;
  830.     offset = pWE->selStart;
  831.  
  832.     // return an error code if this instance is read-only
  833.     err = weReadOnlyErr;
  834.     if (BTST(pWE->features, weFReadOnly))
  835.     {
  836.         goto cleanup;
  837.     }
  838.  
  839.     // stop any ongoing inline input session
  840.     WEStopInlineSession(hWE);
  841.  
  842.     // increment modification count
  843.     pWE->modCount++;
  844.  
  845.     // if undo support is enabled, save current selection range
  846.     if (BTST(pWE->features, weFUndoSupport))
  847.     {
  848.         WEClearUndo(hWE);
  849.         if (_WENewAction(offset, pWE->selEnd, textLength, weAKUnspecified, 0, hWE, &hAction) == noErr)
  850.         {
  851.             _WEPushAction(hAction);
  852.         }
  853.     }
  854.  
  855.     // delete current selection
  856.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  857.     {
  858.         goto cleanup;
  859.     }
  860.  
  861.     // insert the new text at the insertion point
  862.     if ((err = _WEInsertText(offset, textPtr, textLength, hWE)) != noErr)
  863.     {
  864.         goto cleanup;
  865.     }
  866.     endOffset = offset + textLength;
  867.  
  868.     if (hStyles != nil)
  869.     {
  870.  
  871.         // if a style scrap was supplied, apply it to the newly inserted text
  872.         if ((err = _WEApplyStyleScrap(offset, endOffset, hStyles, hWE)) != noErr)
  873.         {
  874.             goto cleanup;
  875.         }
  876.     }
  877.  
  878. #if WASTE_OBJECTS
  879.     if (hSoup != nil)
  880.     {
  881.         // if an object soup was supplied, apply it to the newly inserted text
  882.         if ((err = _WEApplySoup(offset, hSoup, hWE)) != noErr)
  883.         {
  884.             goto cleanup;
  885.         }
  886.     }
  887. #endif
  888.  
  889.     // determine whether an extra space should be added before or after the inserted text
  890.     intPasteAction = _WEIntelligentPaste(offset, endOffset, hWE);
  891.  
  892.     // add the extra space, if necessary
  893.     if (intPasteAction != weDontAddSpaces)
  894.     {
  895.         if (intPasteAction == weAddSpaceOnLeftSide)
  896.         {
  897.             err = _WEInsertText(offset, &space, sizeof(space), hWE);
  898.         }
  899.         else
  900.         {
  901.             err = _WEInsertText(endOffset, &space, sizeof(space), hWE);
  902.         }
  903.         if (err != noErr)
  904.         {
  905.             goto cleanup;
  906.         }
  907.         endOffset++;
  908.  
  909.         // adjust undo buffer (if any) for the extra space
  910.         _WEAdjustUndoRange(sizeof(space), hWE);
  911.     }
  912.  
  913.     // invalid the null style
  914.     BCLR(pWE->flags, weFUseNullStyle);
  915.  
  916.     // move the insertion point at the end of the inserted text
  917.     pWE->selStart = endOffset;
  918.     pWE->selEnd = endOffset;
  919.  
  920.     // redraw the text
  921.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  922.     {
  923.         goto cleanup;
  924.     }
  925.  
  926.     // clear result code
  927.     err = noErr;
  928.  
  929. cleanup:
  930.     // unlock the WE record
  931.     _WESetHandleLock((Handle) hWE, saveWELock);
  932.  
  933.     // return result code
  934.     return err;
  935. }
  936.  
  937. #if WASTE_OBJECTS
  938.  
  939. pascal OSErr WEInsertObject(FlavorType objectType, Handle objectDataHandle, Point objectSize, WEHandle hWE)
  940. {
  941.     WEPtr pWE;
  942.     WEActionHandle hAction;
  943.     SInt32 offset, endOffset;
  944.     WETextStyle ts;
  945.     Boolean saveWELock;
  946.     char marker = kObjectMarker;
  947.     OSErr err;
  948.  
  949.     BLOCK_CLR(ts);
  950.  
  951.     // lock the WE record
  952.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  953.     pWE = *hWE;
  954.     offset = pWE->selStart;
  955.  
  956.     // return an error code if this instance is read-only
  957.     err = weReadOnlyErr;
  958.     if (BTST(pWE->features, weFReadOnly))
  959.     {
  960.         goto cleanup;
  961.     }
  962.  
  963.     // stop any ongoing inline input session
  964.     WEStopInlineSession(hWE);
  965.  
  966.     // call the 'new' handler to initialize private object storage (if any)
  967.     // and to calculate the default size for this object
  968.  
  969.     if ((err = _WENewObject(objectType, objectDataHandle, hWE, &ts.tsObject)) != noErr)
  970.     {
  971.         goto cleanup;
  972.     }
  973.  
  974.     // use the specified object size, unless it is (0, 0), in which case keep the default size
  975.     if (* (SInt32 *) &objectSize != 0)
  976.     {
  977.         (*ts.tsObject)->objectSize = objectSize;
  978.     }
  979.  
  980.     // increment modification count
  981.     pWE->modCount++;
  982.  
  983.     // if undo support is enabled, save current selection range
  984.     if (BTST(pWE->features, weFUndoSupport))
  985.     {
  986.         WEClearUndo(hWE);
  987.         if (_WENewAction(offset, pWE->selEnd, 1, weAKUnspecified, 0, hWE, &hAction) == noErr)
  988.         {
  989.             _WEPushAction(hAction);
  990.         }
  991.     }
  992.  
  993.     // delete current selection
  994.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  995.     {
  996.         goto cleanup;
  997.     }
  998.  
  999.     // insert a kObjectMarker character at the insertion point
  1000.     if ((err = _WEInsertText(offset, &marker, sizeof(marker), hWE)) != noErr)
  1001.     {
  1002.         goto cleanup;
  1003.     }
  1004.  
  1005.     // move the insertion point after the inserted text
  1006.     endOffset = offset + 1;
  1007.     pWE->selStart = endOffset;
  1008.     pWE->selEnd = endOffset;
  1009.  
  1010.     // record a reference to the object descriptor in the style table
  1011.     err = _WESetStyleRange(offset, endOffset, weDoObject, &ts, hWE);
  1012.     ts.tsObject = nil;
  1013.     if (err != noErr)
  1014.     {
  1015.         goto cleanup;
  1016.     }
  1017.  
  1018.     // invalid the null style
  1019.     BCLR(pWE->flags, weFUseNullStyle);
  1020.  
  1021.     // redraw the text
  1022.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  1023.     {
  1024.         goto cleanup;
  1025.     }
  1026.  
  1027.     // clear result code
  1028.     err = noErr;
  1029.  
  1030. cleanup:
  1031.     // clean up
  1032.     _WEForgetHandle((Handle *) &ts.tsObject);
  1033.  
  1034.     // unlock the WE record
  1035.     _WESetHandleLock((Handle) hWE, saveWELock);
  1036.  
  1037.     // return result code
  1038.     return err;
  1039. }
  1040.  
  1041. #endif
  1042.  
  1043. pascal OSErr WEDelete(WEHandle hWE)
  1044. {
  1045.     WEPtr pWE;
  1046.     WEActionHandle hAction;
  1047.     SInt32 rangeStart, rangeEnd;
  1048.     Boolean saveWELock;
  1049.     OSErr err;
  1050.  
  1051.     // lock the WE record
  1052.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1053.     pWE = *hWE;
  1054.  
  1055.     // return an error code if this instance is read-only
  1056.     err = weReadOnlyErr;
  1057.     if (BTST(pWE->features, weFReadOnly))
  1058.     {
  1059.         goto cleanup;
  1060.     }
  1061.  
  1062.     // stop any ongoing inline input session
  1063.     WEStopInlineSession(hWE);
  1064.  
  1065.     // get current selection range
  1066.     rangeStart = pWE->selStart;
  1067.     rangeEnd = pWE->selEnd;
  1068.  
  1069.     // do nothing if the selection range is empty
  1070.     if (rangeStart < rangeEnd)
  1071.     {
  1072.  
  1073.         // increment modification count
  1074.         pWE->modCount++;
  1075.  
  1076.         // range extension for intelligent cut-and-paste
  1077.         _WEIntelligentCut(&rangeStart, &rangeEnd, hWE);
  1078.  
  1079.         // if undo support is enabled, save the range to be deleted
  1080.         if (BTST(pWE->features, weFUndoSupport))
  1081.         {
  1082.             WEClearUndo(hWE);
  1083.             if (_WENewAction(rangeStart, rangeEnd, 0, weAKClear, 0, hWE, &hAction) == noErr)
  1084.             {
  1085.                 _WEPushAction(hAction);
  1086.             }
  1087.         }
  1088.  
  1089.         // delete the selection range
  1090.         if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  1091.         {
  1092.             goto cleanup;
  1093.         }
  1094.  
  1095.         // reset the selection range
  1096.         pWE->selStart = rangeStart;
  1097.         pWE->selEnd = rangeStart;
  1098.  
  1099.         // redraw the text
  1100.         if ((err = _WERedraw(rangeStart, rangeStart, hWE)) != noErr)
  1101.         {
  1102.             goto cleanup;
  1103.         }
  1104.     } // if non-empty selection
  1105.  
  1106.     // clear result code
  1107.     err = noErr;
  1108.  
  1109. cleanup:
  1110.     // unlock the WE record
  1111.     _WESetHandleLock((Handle) hWE, saveWELock);
  1112.  
  1113.     // return result code
  1114.     return err;
  1115. }
  1116.  
  1117. pascal OSErr WECut(WEHandle hWE)
  1118. {
  1119.     OSErr err;
  1120.  
  1121.     // first copy...
  1122.     if ((err = WECopy(hWE)) != noErr)
  1123.     {
  1124.         goto cleanup;
  1125.     }
  1126.  
  1127.     // ... then delete
  1128.     if ((err = WEDelete(hWE)) != noErr)
  1129.     {
  1130.         goto cleanup;
  1131.     }
  1132.  
  1133.     // change the action kind of the most recent action, if any
  1134.     if ((*hWE)->hActionStack != nil)
  1135.     {
  1136.         (*(*hWE)->hActionStack)->actionKind = weAKCut;
  1137.     }
  1138.  
  1139. cleanup:
  1140.     // return result code
  1141.     return err;
  1142. }
  1143.  
  1144. pascal Boolean WECanPaste(WEHandle hWE)
  1145. {
  1146.     SInt32 scrapOffset;
  1147. #if WASTE_OBJECTS
  1148.     FlavorType objectType;
  1149.     SInt32 index;
  1150. #endif
  1151.  
  1152.     if (!BTST((*hWE)->features, weFReadOnly))
  1153.     {
  1154.         // return true if the desk scrap contains a text flavor
  1155.         if (GetScrap(nil, kTypeText, &scrapOffset) > 0)
  1156.         {
  1157.             return true;
  1158.         }
  1159.  
  1160. #if WASTE_OBJECTS
  1161.         // see if the desk scrap contains a flavor matching one of the registered object types
  1162.         index = 0;
  1163.         while (_WEGetIndObjectType(index, &objectType, hWE) == noErr)
  1164.         {
  1165.             if (GetScrap(nil, objectType, &scrapOffset) > 0)
  1166.             {
  1167.                 return true;
  1168.             }
  1169.             index++;
  1170.         } // while
  1171. #endif
  1172.     } // if not read-only
  1173.     return false;
  1174. }
  1175.  
  1176. pascal OSErr WEPaste(WEHandle hWE)
  1177. {
  1178.     Handle hItem = nil;
  1179.     Handle hStyles = nil;
  1180.     Handle hSoup = nil;
  1181.     SInt32 scrapOffset;
  1182. #if WASTE_OBJECTS
  1183.     FlavorType objectType;
  1184.     SInt32 index;
  1185. #endif
  1186.     OSErr err;
  1187.  
  1188.     // allocate a handle to hold a scrap item
  1189.     if ((err = _WEAllocate(0, kAllocTemp, &hItem)) != noErr)
  1190.     {
  1191.         goto cleanup;
  1192.     }
  1193.  
  1194.     // look for a text flavor
  1195.     if (GetScrap(hItem, kTypeText, &scrapOffset) <= 0)
  1196.     {
  1197.  
  1198. #if WASTE_OBJECTS
  1199.         // no text: look for a flavor matching one of the registered object types
  1200.         index = 0;
  1201.         while (_WEGetIndObjectType(index, &objectType, hWE) == noErr)
  1202.         {
  1203.             if (GetScrap(hItem, objectType, &scrapOffset) > 0)
  1204.             {
  1205.                 Point objectSize;
  1206.                 * (SInt32 *) &objectSize = 0;
  1207.  
  1208.                 // found a registered type: create a new object out of the tagged data
  1209.                 err = WEInsertObject(objectType, hItem, objectSize, hWE);
  1210.  
  1211.                 // if successful, set hItem to nil so clean-up section won't kill the object data
  1212.                 if (err == noErr)
  1213.                 {
  1214.                     hItem = nil;
  1215.                 }
  1216.                 goto cleanup;
  1217.             }
  1218.  
  1219.             // try with next flavor
  1220.             index++;
  1221.         } // while
  1222. #endif
  1223.  
  1224.         // nothing pasteable: return an error code
  1225.         err = noTypeErr;
  1226.         goto cleanup;
  1227.     }
  1228.  
  1229.     if (!BTST((*hWE)->features, weFMonoStyled))
  1230.     {
  1231.         // allocate a handle to hold the style scrap, if any
  1232.         if ((err = _WEAllocate(0, kAllocTemp, &hStyles)) != noErr)
  1233.         {
  1234.             goto cleanup;
  1235.         }
  1236.  
  1237.         // look for a 'styl' item accompanying the text
  1238.         if (GetScrap(hStyles, kTypeStyles, &scrapOffset) <= 0)
  1239.         {
  1240.             // forget the handle if nothing was found or an error occurred
  1241.             _WEForgetHandle(&hStyles);
  1242.         }
  1243.  
  1244. #if WASTE_OBJECTS
  1245.         // allocate a handle to hold the soup, if any
  1246.         if ((err = _WEAllocate(0, kAllocTemp, &hSoup)) != noErr)
  1247.         {
  1248.             goto cleanup;
  1249.         }
  1250.  
  1251.         // look for a 'SOUP' item accompanying the text
  1252.         if (GetScrap(hSoup, kTypeSoup, &scrapOffset) <= 0)
  1253.         {
  1254.             // forget the handle if nothing was found or an error occurred
  1255.             _WEForgetHandle(&hSoup);
  1256.         }
  1257. #endif
  1258.     } // if not mono-styled
  1259.  
  1260.     // lock down the text
  1261.     HLock(hItem);
  1262.  
  1263.     // insert the text
  1264.     err = WEInsert(*hItem, GetHandleSize(hItem), (StScrpHandle) hStyles, hSoup, hWE);
  1265.  
  1266. cleanup:
  1267.     // if successful, change the action kind of the most recent action, if any
  1268.     if ((err == noErr) && ((*hWE)->hActionStack != nil))
  1269.     {
  1270.         (*(*hWE)->hActionStack)->actionKind = weAKPaste;
  1271.     }
  1272.  
  1273.     // clean up
  1274.     _WEForgetHandle(&hItem);
  1275.     _WEForgetHandle(&hStyles);
  1276. #if WASTE_OBJECTS
  1277.     _WEForgetHandle(&hSoup);
  1278. #endif
  1279.  
  1280.     // return result code
  1281.     return err;
  1282. }
  1283.  
  1284. pascal OSErr _WESmartSetFont(WEStyleMode mode, const TextStyle *ts, WEHandle hWE)
  1285. {
  1286.     WEPtr pWE = *hWE;    // assume WE record is already locked
  1287.     ScriptCode script;
  1288.     SInt32 runIndex;
  1289.     SInt32 rangeStart, rangeEnd;
  1290.     WERunInfo runInfo;
  1291.     GrafPtr savePort;
  1292.     SInt16 saveFont;
  1293.     OSErr err;
  1294.  
  1295.     // set up the graphics port
  1296.     GetPort(&savePort);
  1297.     SetPort(pWE->port);
  1298.     saveFont = pWE->port->txFont;
  1299.  
  1300.     // get the script corresponding to the font we're applying
  1301.     script = FontToScript(ts->tsFont);
  1302.  
  1303.     // walk through the style runs encompassing the selection range
  1304.     runIndex = WEOffsetToRun(pWE->selStart, hWE);
  1305.     do
  1306.     {
  1307.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  1308.  
  1309.         if (pWE->selStart > runInfo.runStart)
  1310.         {
  1311.             rangeStart = pWE->selStart;
  1312.         }
  1313.         else
  1314.         {
  1315.             rangeStart = runInfo.runStart;
  1316.         }
  1317.  
  1318.         if (pWE->selEnd < runInfo.runEnd)
  1319.         {
  1320.             rangeEnd = pWE->selEnd;
  1321.         }
  1322.         else
  1323.         {
  1324.             rangeEnd = runInfo.runEnd;
  1325.         }
  1326.  
  1327.         // does this style run belong to the same script we're applying?
  1328.         if (FontToScript(runInfo.runAttrs.runStyle.tsFont) == script)
  1329.         {
  1330.             if ((err = _WESetStyleRange(rangeStart, rangeEnd, weDoFont, (WETextStyle *) ts, hWE)) != noErr)
  1331.             {
  1332.                 goto cleanup;
  1333.             }
  1334.             runIndex = WEOffsetToRun(runInfo.runEnd, hWE);
  1335.         }
  1336.         else if ((mode & weDoExtractSubscript) != 0)
  1337.         {
  1338.             SInt32 runLength;
  1339.             SInt32 subrunLength;
  1340.             ScriptRunStatus runStatus;
  1341.  
  1342.             // FindScriptRun takes an implicit parameter through the txFont field of thePort
  1343.             TextFont(runInfo.runAttrs.runStyle.tsFont);
  1344.  
  1345.             runLength = rangeEnd - rangeStart;
  1346.             while (runLength > 0)
  1347.             {
  1348.                 // lock text handle
  1349.                 Boolean saveTextLock = _WESetHandleLock(pWE->hText, true);
  1350.  
  1351.                 // look for blocks of subscript text
  1352.                 runStatus = FindScriptRun(*pWE->hText + rangeStart, runLength, &subrunLength);
  1353.  
  1354.                 // unlock text handle
  1355.                 _WESetHandleLock(pWE->hText, saveTextLock);
  1356.  
  1357.                 if (runStatus.script == script)
  1358.                 {
  1359.                     // "extract" subscript text
  1360.                     if ((err = _WESetStyleRange(rangeStart, rangeStart + subrunLength, weDoFont, (WETextStyle *) ts, hWE)) != noErr)
  1361.                     {
  1362.                         goto cleanup;
  1363.                     }
  1364.                 }
  1365.                 rangeStart += subrunLength;
  1366.                 runLength -= subrunLength;
  1367.             }
  1368.             runIndex = WEOffsetToRun(runInfo.runEnd, hWE);
  1369.         }
  1370.         else
  1371.             runIndex++;
  1372.  
  1373.     } while (runInfo.runEnd < pWE->selEnd);
  1374.  
  1375. cleanup:
  1376.     // restore the port
  1377.     TextFont(saveFont);
  1378.     SetPort(savePort);
  1379.  
  1380.     // return result code
  1381.     return err;
  1382. }
  1383.  
  1384. pascal OSErr WESetStyle(WEStyleMode mode, const TextStyle *ts, WEHandle hWE)
  1385. {
  1386.     WEPtr pWE;
  1387.     WEActionHandle hAction;
  1388.     ScriptCode fontScript;
  1389.     Boolean saveWELock;
  1390.     OSErr err;
  1391.  
  1392.     // lock the WE record
  1393.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1394.     pWE = *hWE;
  1395.  
  1396.     // return an error code if this instance is read-only
  1397.     err = weReadOnlyErr;
  1398.     if (BTST(pWE->features, weFReadOnly))
  1399.     {
  1400.         goto cleanup;
  1401.     }
  1402.  
  1403.     // stop any ongoing inline input session
  1404.     WEStopInlineSession(hWE);
  1405.  
  1406.     if (BTST(pWE->features, weFMonoStyled))
  1407.     {
  1408.         // MONOSTYLED TEXT
  1409.         // apply the change to the whole text, not just to the selection range
  1410.         if ((err = _WESetStyleRange(0, pWE->textLength, mode, (WETextStyle *) ts, hWE)) != noErr)
  1411.         {
  1412.             goto cleanup;
  1413.         }
  1414.  
  1415.         // redraw the text
  1416.         if ((err = _WERedraw(0, pWE->textLength, hWE)) != noErr)
  1417.         {
  1418.             goto cleanup;
  1419.         }
  1420.     }
  1421.     else if (pWE->selStart == pWE->selEnd)
  1422.     {
  1423.         // MULTISTYLED TEXT; NULL SELECTION
  1424.         // first make sure the nullStyle field contains valid information
  1425.         _WESynchNullStyle(hWE);
  1426.  
  1427.         // apply style changes to the nullStyle record
  1428.         _WECopyStyle((WETextStyle *) ts, &pWE->nullStyle.runStyle, pWE->nullStyle.runStyle.tsFace, mode);
  1429.  
  1430.         // special case: if this instance is empty, propagate the
  1431.         // change to the style table (this avoids some subtle problems)
  1432.         if (pWE->textLength == 0)
  1433.         {
  1434.             if ((err = _WESetStyleRange(0, 0, weDoAll + weDoReplaceFace, &pWE->nullStyle.runStyle, hWE)) != noErr)
  1435.             {
  1436.                 goto cleanup;
  1437.             }
  1438.         }
  1439.  
  1440. #if !WASTE_NO_SYNCH
  1441.         // if the font was altered, synchronize the keyboard script
  1442.         if (BTST(pWE->flags, weFNonRoman) && (mode & weDoFont))
  1443.         {
  1444.             fontScript = FontToScript(pWE->nullStyle.runStyle.tsFont);
  1445.             if (fontScript != GetScriptManagerVariable(smKeyScript))
  1446.             {
  1447.                 KeyScript(fontScript);
  1448.             }
  1449.         }
  1450. #endif
  1451.     }
  1452.     else
  1453.     {
  1454.         // MULTISTYLED TEXT; NON-EMPTY SELECTION
  1455.  
  1456.         // increment modification count
  1457.         pWE->modCount++;
  1458.  
  1459.         // if undo support is enabled, save the styles of the text range to be affected
  1460.         if (BTST(pWE->features, weFUndoSupport))
  1461.         {
  1462.             WEClearUndo(hWE);
  1463.             if (_WENewAction(pWE->selStart, pWE->selEnd, pWE->selEnd - pWE->selStart, weAKSetStyle,
  1464.                 weAFDontSaveText + weAFDontSaveSoup, hWE, &hAction) == noErr)
  1465.             {
  1466.                 _WEPushAction(hAction);
  1467.             }
  1468.         }
  1469.  
  1470.         // check for "smart" font modes
  1471.         if (BTST(pWE->flags, weFNonRoman) && ((mode & weDoSmartFont) == weDoSmartFont))
  1472.         {
  1473.             if ((err = _WESmartSetFont(mode, ts, hWE)) != noErr)
  1474.             {
  1475.                 goto cleanup;
  1476.             }
  1477.             mode &= ~weDoFont;
  1478.         }
  1479.  
  1480.         // set the style of the selection range
  1481.         if ((err = _WESetStyleRange(pWE->selStart, pWE->selEnd, mode, (WETextStyle *) ts, hWE)) != noErr)
  1482.         {
  1483.             goto cleanup;
  1484.         }
  1485.  
  1486.         // and redraw the text
  1487.         if ((err = _WERedraw(pWE->selStart, pWE->selEnd, hWE)) != noErr)
  1488.         {
  1489.             goto cleanup;
  1490.         }
  1491.     }
  1492.  
  1493.     // clear the result code
  1494.     err = noErr;
  1495.  
  1496. cleanup:
  1497.     // unlock the WE record
  1498.     _WESetHandleLock((Handle) hWE, saveWELock);
  1499.  
  1500.     // return result code
  1501.     return err;
  1502. }
  1503.  
  1504. pascal OSErr WEUseStyleScrap(StScrpHandle hStyles, WEHandle hWE)
  1505. {
  1506.     WEPtr pWE;
  1507.     Boolean saveWELock;
  1508.     OSErr err;
  1509.  
  1510.     // lock the WE record
  1511.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1512.     pWE = *hWE;
  1513.  
  1514.     // return an error code if this instance is read-only
  1515.     err = weReadOnlyErr;
  1516.     if (BTST(pWE->features, weFReadOnly))
  1517.     {
  1518.         goto cleanup;
  1519.     }
  1520.  
  1521.     // apply the style scrap to the selection range
  1522.     if ((err = _WEApplyStyleScrap(pWE->selStart, pWE->selEnd, hStyles, hWE)) != noErr)
  1523.     {
  1524.         goto cleanup;
  1525.     }
  1526.  
  1527.     // redraw the text
  1528.     err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  1529.  
  1530. cleanup:
  1531.     // unlock the WE record
  1532.     _WESetHandleLock((Handle) hWE, saveWELock);
  1533.  
  1534.     // return result code
  1535.     return err;
  1536. }
  1537.  
  1538. #if WASTE_OBJECTS
  1539.  
  1540. pascal OSErr WEUseSoup(Handle hSoup, WEHandle hWE)
  1541. {
  1542.     WEPtr pWE;
  1543.     Boolean saveWELock;
  1544.     OSErr err;
  1545.  
  1546.     // lock the WE record
  1547.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1548.     pWE = *hWE;
  1549.  
  1550.     // return an error code if this instance is read-only
  1551.     err = weReadOnlyErr;
  1552.     if (BTST(pWE->features, weFReadOnly))
  1553.     {
  1554.         goto cleanup;
  1555.     }
  1556.  
  1557.     // apply the soup starting from selStart
  1558.     if ((err = _WEApplySoup(pWE->selStart, hSoup, hWE)) != noErr)
  1559.     {
  1560.         goto cleanup;
  1561.     }
  1562.  
  1563.     // redraw the text
  1564.     err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  1565.  
  1566. cleanup:
  1567.     // unlock the WE record
  1568.     _WESetHandleLock((Handle) hWE, saveWELock);
  1569.  
  1570.     // return result code
  1571.     return err;
  1572. }
  1573.  
  1574. #endif  // WASTE_OBJECTS
  1575.